package CheckersApplet;

import java.util.ArrayList;
import java.util.Date;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.*;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

public class CheckersAgent extends Agent {

	private CheckersGUI myGui;
	private String color;
	private String oppName;
	private int thougness = 3;
	private GameState gameState = GameState.NOTSTARTED;
	private String tournamentAgent = "";
	private final int MaxMoves = 50;
	private int movesCount = 0;
	private final int WaitForOpponentInterval = 500;
	private final int MakeMoveInterval = 200;
	
	protected void setup() {
		// Printout a welcome message
		System.out.println("Hello! Checker-agent " + getAID().getName()
				+ " is ready.");

		Object[] args = getArguments();
		if (args != null && args.length > 0) {
			//color = (String) args[0];
			// System.out.println("My color is : " + color);
			thougness = Integer.parseInt((String) args[0]);
		}

		myGui = new CheckersGUI(this);

		if (myGui == null) {
			System.out.println("Cannot create GUI!");
			takeDown();
		}

		//myGui.setColor(color);

		myGui.setThougnss(thougness);
		myGui.showGui();

		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(getAID());
		ServiceDescription sd = new ServiceDescription();
		sd.setType("checkers-player");
		sd.setName("JADE-checkers-tournament");
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		} catch (FIPAException fe) {
			fe.printStackTrace();
		}

		addBehaviour(new WaitForOpponentBehaviour(this, WaitForOpponentInterval));
	}

	private class WaitForOpponentBehaviour extends WakerBehaviour {

		public WaitForOpponentBehaviour(Agent a, long timeout) {
			super(a, timeout);
		}

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void handleElapsedTimeout() {
			MessageTemplate mt = MessageTemplate
					.MatchPerformative(ACLMessage.PROPOSE);
			ACLMessage msg = myAgent.receive(mt);
			if (msg != null) {
				// Message received. Process it
				// System.out.println(color + " Message received: "
				// + msg.getContent());
				if (tournamentAgent.equals(""))
					tournamentAgent = msg.getSender().getLocalName();
				// System.out.println("tournament agent is " + tournamentAgent);
				String[] tab = msg.getContent().split(" ");
				oppName = tab[0];
				color = tab[1];
				//System.out.println(getAID().getLocalName() + ": opp agent is "
				//		+ oppName + " my color is " + color);
				myGui.setColor(color);
				String move = Move.ArrayListToString(myGui.newGame());
				myGui.repaint();

				if (color.equals("red")) { // I start, send the first move
					// System.out.println(getAID().getLocalName() +
					// " Message sent: " + move);
					ACLMessage replyMsg = new ACLMessage(ACLMessage.INFORM);
					replyMsg.addReceiver(new AID(oppName, AID.ISLOCALNAME));
					replyMsg.setContent(move);
					send(replyMsg);
				}
				addBehaviour(new MakeMoveBeahaviour(myAgent, MakeMoveInterval));
				gameState = GameState.INPROGRESS;
				movesCount = 0;
			} else {
				addBehaviour(new WaitForOpponentBehaviour(myAgent, WaitForOpponentInterval));
			}
		}
	}

	private class MakeMoveBeahaviour extends TickerBehaviour {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public MakeMoveBeahaviour(Agent a, long period) {
			super(a, period);
			// TODO Auto-generated constructor stub
		}

		@Override
		protected void onTick() {
			MessageTemplate mt = MessageTemplate
					.MatchPerformative(ACLMessage.INFORM);
			ACLMessage msg = myAgent.receive(mt);
			if (msg != null && msg.getSender().getLocalName().equals(oppName)) {
				// Message received. Process it
				// System.out.println(getAID().getLocalName()
				// + ": Message received: " + msg.getContent());

				if (msg.getContent().equals("")) {
//					System.out.println(getAID().getLocalName()
//							+ " EMPTY MSG RECV");
//					if (myGui.getGameState() == GameState.REDWON)
//						System.out.println("REDWON");
//					if (myGui.getGameState() == GameState.BLACKWON)
//						System.out.println("BLACKWON");
					if (color.equals("black")
							&& myGui.getGameState() == GameState.BLACKWON) {
						//System.out.println(color + " won ");
						myAgent.removeBehaviour(this);
						sendScore("1");
					} else if (color.equals("red")
							&& myGui.getGameState() == GameState.REDWON) {
						//System.out.println(color + " won ");
						myAgent.removeBehaviour(this);
						sendScore("1");
					} else {
						myAgent.removeBehaviour(this);
						sendScore("-1");
					}
				}

				if (myGui.getGameState() != GameState.INPROGRESS)
					return;
				ArrayList<Move> moves = null;
				try {
					moves = Move.StringToArrayList(msg.getContent());
				} catch (Exception e) {
					return;
				}

				String reply = Move.ArrayListToString(myGui.makeMove(moves));
				myGui.repaint();

				ACLMessage replyMsg = new ACLMessage(ACLMessage.INFORM);
				replyMsg.addReceiver(new AID(oppName, AID.ISLOCALNAME));
				replyMsg.setContent(reply);
				// System.out.println(color + " Message sent: " + reply);

				if (reply.equals("")) {
//					System.out.println(getAID().getLocalName()
//							+ " EMPTY MSG SENT");
//					if (myGui.getGameState() == GameState.REDWON)
//						System.out.println("REDWON");
//					if (myGui.getGameState() == GameState.BLACKWON)
//						System.out.println("BLACKWON");
					
					if (color.equals("red")
							&& myGui.getGameState() == GameState.REDWON) {
						//System.out.println(color + " won ");
						myAgent.removeBehaviour(this);
						sendScore("1");
					} else if (color.equals("black")
							&& myGui.getGameState() == GameState.BLACKWON) {
						//System.out.println(color + " won ");
						myAgent.removeBehaviour(this);
						sendScore("1");
					} else {
						myAgent.removeBehaviour(this);
						sendScore("1");
					}
				}
				send(replyMsg);
				movesCount++;
//				System.out.println(getAID().getLocalName() + " "
//						+ String.valueOf(movesCount));
				if (movesCount == MaxMoves) {
					myAgent.removeBehaviour(this);
					sendScore("0");
					gameState = GameState.TIE;
				}
			} else {
				block();
			}
		}
	}

	private void sendScore(String reply) {
		ACLMessage replyMsg = new ACLMessage(ACLMessage.INFORM);
		replyMsg.addReceiver(new AID(tournamentAgent, AID.ISLOCALNAME));
		replyMsg.setContent(reply);
		//System.out.println(getAID().getLocalName() + ": message sent: " + reply
		//		+ " to: " + tournamentAgent);
		send(replyMsg);
		gameState = GameState.NOTSTARTED;
		addBehaviour(new WaitForOpponentBehaviour(this, WaitForOpponentInterval));
	}

	protected void takeDown() {
		try {
			DFService.deregister(this);
		} catch (FIPAException fe) {
			fe.printStackTrace();
		}
		myGui.dispose();
		System.out.println("Checkers-agent " + getAID().getName()
				+ " terminating.");
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

}
